package top.xiaozhaobk.xiaofenshu.auth.service.impl;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.google.common.base.Preconditions;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import top.xiaozhaobk.framework.biz.context.filter.LoginUserContextHolder;
import top.xiaozhaobk.framework.common.exception.BizException;
import top.xiaozhaobk.framework.common.response.Response;
import top.xiaozhaobk.xiaofenshu.auth.constant.RedisKeyConstants;
import top.xiaozhaobk.xiaofenshu.auth.enums.LoginTypeEnum;
import top.xiaozhaobk.xiaofenshu.auth.enums.ResponseCodeEnum;
import top.xiaozhaobk.xiaofenshu.auth.model.vo.user.UpdatePasswordReqVO;
import top.xiaozhaobk.xiaofenshu.auth.model.vo.user.UserLoginReqVO;
import top.xiaozhaobk.xiaofenshu.auth.rpc.UserRpcService;
import top.xiaozhaobk.xiaofenshu.auth.service.AuthService;
import top.xiaozhaobk.xiaofenshu.user.dto.resp.FindUserByPhoneRspDTO;

import java.util.Objects;

@Service
@Slf4j
public class AuthServiceImpl implements AuthService {
    @Resource
    private UserRpcService userRpcService;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    public Response<String> loginAndRegister(UserLoginReqVO userLoginReqVO) {
        String phone = userLoginReqVO.getPhone();
        Integer type = userLoginReqVO.getType();

        //判断登陆类型
        LoginTypeEnum loginTypeEnum = LoginTypeEnum.valueOf(type);
        Preconditions.checkArgument(Objects.nonNull(loginTypeEnum),ResponseCodeEnum.LOGIN_TYPE_ERROR.getErrorMessage());

        Long userId = null;
        switch (loginTypeEnum) {
            case PASSWORD -> {
                String password = userLoginReqVO.getPassword();

                // RPC: 调用用户服务，通过手机号查询用户
                FindUserByPhoneRspDTO findUserByPhoneRspDTO = userRpcService.findUserByPhone(phone);

                // 判断该手机号是否注册
                if (Objects.isNull(findUserByPhoneRspDTO)) {
                    throw new BizException(ResponseCodeEnum.USER_NOT_FOUND);
                }

                // 拿到密文密码
                String encodePassword = findUserByPhoneRspDTO.getPassword();

                // 匹配密码是否一致
                boolean isPasswordCorrect = passwordEncoder.matches(password, encodePassword);

                // 如果不正确，则抛出业务异常，提示用户名或者密码不正确
                if (!isPasswordCorrect) {
                    throw new BizException(ResponseCodeEnum.PHONE_OR_PASSWORD_ERROR);
                }

                userId = findUserByPhoneRspDTO.getId();
            }
            case VERIFICATION_CODE -> {
                //验证码登录
                String code = userLoginReqVO.getCode();
                Preconditions.checkArgument(StringUtils.isNotBlank(code),"验证码不能为空");

                String key = RedisKeyConstants.buildVerificationCodeKey(phone);
                String sentCode = (String) redisTemplate.opsForValue().get(key);
                //验证码比较
                Preconditions.checkArgument(StringUtils.equals(code, sentCode),"验证码错误");

                // RPC: 调用用户服务，注册用户
                Long userIdTmp = userRpcService.registerUser(phone);

                // 若调用用户服务，返回的用户 ID 为空，则提示登录失败
                if (Objects.isNull(userIdTmp)) {
                    throw new BizException(ResponseCodeEnum.LOGIN_FAIL);
                }

                userId = userIdTmp;
            }
            default -> {
            }
        }

        StpUtil.login(userId);

        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();

        return Response.success(tokenInfo.tokenValue);
    }

    @Override
    public Response<?> logout() {
        Long userId = LoginUserContextHolder.getUserId();
        StpUtil.logout(userId);
        return Response.success();
    }

    @Override
    public Response<?> updatePassword(UpdatePasswordReqVO updatePasswordReqVO) {
        // 新密码
        String newPassword = updatePasswordReqVO.getNewPassword();
        // 密码加密
        String encodePassword = passwordEncoder.encode(newPassword);

        // RPC: 调用用户服务：更新密码
        userRpcService.updatePassword(encodePassword);

        return Response.success();
    }
}
